/*
 * StructXml.cpp
 *
 *  Created on: 2015年7月11日
 *      Author: chuanjiang.zh@qq.com
 */

#include "StructXml.h"
#include "XmlBuilder.h"
#include "TinyXmlUtil.h"
#include "BasicMacro.h"


namespace gb
{

size_t extract(const std::string& str, size_t offset, char chBegin, char chEnd, std::string& value)
{
    size_t idx = str.find(chBegin, offset);
    if (idx == std::string::npos)
    {
        return std::string::npos;
    }

    size_t idxEnd = str.find(chEnd, idx + 1);
    if (idxEnd == std::string::npos)
    {
        return std::string::npos;
    }

    value = str.substr(idx + 1, idxEnd - idx - 1);
    return idxEnd;
}


bool parse(const std::string& xml, Command& cmd)
{
    if (xml.empty())
    {
        return false;
    }

    size_t idx = extract(xml, 2, '<', '>', cmd.m_class);
    if (idx == std::string::npos)
    {
        return false;
    }

    idx = extract(xml, idx + 1, '>', '<', cmd.m_type);
    if (idx == std::string::npos)
    {
        return false;
    }

    return true;
}


void cmdToXml(Command& cmd, xml::Node& node)
{
    node.write("CmdType", cmd.m_type);
    node.write("SN", cmd.m_sn);
    node.write("DeviceID", cmd.m_deviceID);
}

void toXml(Request& request, xml::Node& node)
{
    cmdToXml(request, node);
}

void toXml(Response& response, xml::Node& node)
{
    cmdToXml(response, node);
    node.write("Result", response.m_result);
}

void toXml(Notify& notify, xml::Node& node)
{
    cmdToXml(notify, node);
}

void toXml(Query& query, xml::Node& node)
{
    cmdToXml(query, node);
}




bool fromXml(TiXmlDocument& doc, Command& cmd)
{
    TiXmlElement* root = doc.RootElement();
    CheckPointer(root, false);

    TiXmlElement* element = root->FirstChildElement();
    CheckPointer(element, false);
    xml::getValue(element, cmd.m_type);

    element = element->NextSiblingElement();
    CheckPointer(element, false);
    xml::getValue(element, cmd.m_sn);

    element = element->NextSiblingElement();
    CheckPointer(element, false);
    xml::getValue(element, cmd.m_deviceID);

    element = element->NextSiblingElement();
    CheckPointer(element, false);
    //cmd.m_name = element->ValueTStr();

    return true;
}

bool fromXml(TiXmlDocument& doc, Response& resp)
{
    TiXmlElement* root = doc.RootElement();
    CheckPointer(root, false);

    TiXmlElement* element = root->FirstChildElement();
    CheckPointer(element, false);
    xml::getValue(element, resp.m_type);

    element = element->NextSiblingElement();
    CheckPointer(element, false);
    xml::getValue(element, resp.m_sn);

    element = element->NextSiblingElement();
    CheckPointer(element, false);
    xml::getValue(element, resp.m_deviceID);

    element = element->NextSiblingElement();
    CheckPointer(element, false);
    xml::getValue(element, resp.m_result);

    return true;
}

std::string toXml(Query& query)
{
    xml::Document doc(xml::Document::VERSION);
    {
        xml::Node root(doc, QUERY);
        toXml(query, root);
    }
    return doc.str();
}

std::string toXml(Request& request)
{
    xml::Document doc(xml::Document::VERSION);
    {
        xml::Node root(doc, QUERY);
        toXml(request, root);
    }

    return doc.str();
}











bool fromXml(TiXmlDocument& doc, CatalogResponse& obj)
{
    if (!fromXml(doc, (Response&)obj))
    {
        return false;
    }

    TiXmlElement* root = doc.RootElement();
    xml::getValue(root, "SumNum", obj.m_sumNum);

    TiXmlElement* devList = root->FirstChildElement("DeviceList");
    if (!devList)
    {
        return false;
    }

    int num = 0;
    devList->Attribute("Num", &num);

    TiXmlElement* xmlItem = devList->FirstChildElement("Item");
    while (xmlItem)
    {
        DeviceItem item;
        xml::getValue(xmlItem, "DeviceID", item.m_deviceID);
        xml::getValue(xmlItem, "name", item.m_name);
        xml::getValue(xmlItem, "Manufacture", item.m_manufacture);
        xml::getValue(xmlItem, "Model", item.m_model);
        xml::getValue(xmlItem, "ParentID", item.m_parentID);
        xml::getValue(xmlItem, "IPAddress", item.m_ip);
        xml::getValue(xmlItem, "Port", item.m_port);
        xml::getValue(xmlItem, "Status", item.m_status);
        xml::getValue(xmlItem, "Longitude", item.m_longitude);
        xml::getValue(xmlItem, "Latitude", item.m_latitude);

        obj.m_itemList.push_back(item);
    }

    return true;
}


std::string toXml(PtzRequest& request)
{
    xml::Document doc(xml::Document::VERSION);
    {
        xml::Node root(doc, CONTROL);
        toXml(request, root);
        root.write(request.m_name, request.m_ptzCmd);
        xml::Node info(doc, "Info");
        info.write("ControlPriority", request.m_priority);
    }
    return doc.str();
}


std::string toXml(AlarmNotify& obj)
{
    xml::Document doc(xml::Document::VERSION);
    {
        xml::Node root(doc, NOTIFY);
        toXml(obj, root);
        root.write("AlarmPriority", obj.m_priority);
        root.write("AlarmTime", obj.m_time);
        root.write("AlarmMethod", obj.m_method);
        root.write("AlarmDescription", obj.m_desc);

        root.write("Longitude", obj.m_longitude);
        root.write("Latitude", obj.m_latitude);
    }
    return doc.str();
}

bool fromXml(TiXmlDocument& doc, AlarmNotify& obj)
{
    if (!fromXml(doc, (Notify&)obj))
    {
        return false;
    }

    TiXmlElement* root = doc.RootElement();
    xml::getValue(root, "AlarmPriority", obj.m_priority);
    xml::getValue(root, "AlarmTime", obj.m_time);
    xml::getValue(root, "AlarmMethod", obj.m_method);

    return true;
}


bool fromXml(TiXmlDocument& doc, DeviceInfoResponse& obj)
{
    if (!fromXml(doc, (Response&)obj))
    {
        return false;
    }

    TiXmlElement* root = doc.RootElement();
    xml::getValue(root, "DeviceType", obj.m_devType);
    xml::getValue(root, "Manufacturer", obj.m_manufacturer);
    xml::getValue(root, "Model", obj.m_model);
    xml::getValue(root, "Firmware", obj.m_firmware);
    xml::getValue(root, "MaxCamera", obj.m_maxCamera);
    xml::getValue(root, "MaxAlarm", obj.m_maxAlarm);

    return true;
}

bool fromXml(TiXmlDocument& doc, DeviceStatusResponse& obj)
{
    if (!fromXml(doc, (Response&)obj))
    {
        return false;
    }

    TiXmlElement* root = doc.RootElement();
    xml::getValue(root, "Online", obj.m_online);
    xml::getValue(root, "Status", obj.m_status);
    xml::getValue(root, "Encode", obj.m_encode);
    xml::getValue(root, "Record", obj.m_record);
    xml::getValue(root, "DeviceTime", obj.m_time);


    return true;
}

std::string toXml(CatalogQuery& obj)
{
    xml::Document doc(xml::Document::VERSION);
    {
        xml::Node root(doc, QUERY);
        toXml((Query&)obj, root);

        if (!obj.m_startTime.empty())
        {
            root.write("StartTime", obj.m_startTime);
            root.write("StopTime", obj.m_stopTime);
        }
    }
    return doc.str();
}

std::string toXml(BroadcastNotify& obj)
{
	xml::Document doc(xml::Document::VERSION);
	{
		xml::Node root(doc, NOTIFY);
		root.write("CmdType", obj.m_type);
		root.write("SN", obj.m_sn);
		root.write("SourceID", obj.m_sourceID);
		root.write("TargetID", obj.m_targetID);
	}
	return doc.str();
}


} /* namespace gb */
